package com.jlh;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiEnumConstant;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiType;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import org.apache.commons.codec.language.bm.Lang;
import org.apache.commons.lang3.StringUtils;

/**
 * @author mymx.jlh
 * @version 1.0.0 2018/5/25 9:41
 */
public class EnumGenerator extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        PsiFile orinalPsiFile = e.getData(LangDataKeys.PSI_FILE);
        // 获取数据上下文
        DataContext dataContext = e.getDataContext();

        // 获取到数据上下文后，通过CommonDataKeys对象可以获得该File的所有信息
        Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
        PsiFile psiFile = CommonDataKeys.PSI_FILE.getData(dataContext);

        PsiClass psiClass = getPsiClassFromContext(e,psiFile,editor);
        if (psiClass != null && psiClass.isEnum()) {
            solve(psiClass, orinalPsiFile, e);
        }
    }


    private void solve(PsiClass psiClass,PsiFile orinalPsiFile,AnActionEvent e){
        if (psiClass == null){
            return;
        }
        Project project = e.getProject();
        PsiField[] psiFields =psiClass.getFields();
        if (psiFields.length > 0) {
            WriteCommandAction.runWriteCommandAction(project, () -> {
                boolean hasNull = false;
                PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
                //为每个field创建方法
                PsiClassType psiClassType = PsiType.getTypeByName(psiClass.getName(),project, GlobalSearchScope.fileScope(orinalPsiFile));
                for (PsiField psiField : psiFields){
                    if (StringUtils.contains(psiField.getType().getCanonicalText(),psiClassType.getName())){
                        if (StringUtils.contains(psiField.getName(),"Null")){
                            hasNull = true;
                        }
                    }
                    //过滤枚举常量
                    else {
                        addValueOfMethodBody(psiField,psiClass,factory);
                        addGetMethod(psiField,psiClass,factory);
                    }
                }

                //生成默认枚举常量
                if (!hasNull) {
                    PsiEnumConstant psiEnumConstant = factory.createEnumConstantFromText("Null", psiClass);
                    psiClass.add(psiEnumConstant);
                }

                PsiMethod[] cons = psiClass.getConstructors();

                for (PsiMethod con : cons){
                    if (con.getParameters().length == 0){
                        con.delete();
                    }
                }
                //无参构造
                PsiMethod noParamConstructor = factory.createConstructor();
                psiClass.add(noParamConstructor);


            });
        }

    }

    private PsiClass getPsiClassFromContext(AnActionEvent e, PsiFile psiFile, Editor editor) {

        if (psiFile == null || editor == null) {
            return null;
        }
        //获取插入的model，并获取偏移量
        int offset = editor.getCaretModel().getOffset();
        //根据偏移量找到psi元素
        PsiElement element = psiFile.findElementAt(offset);
        //根据元素获取到当前的上下文的类
        return PsiTreeUtil.getParentOfType(element, PsiClass.class);
    }


    /**
     * 添加valueOf方法
     * @param psiField
     * @param psiClass
     * @param factory
     */
    private void addValueOfMethodBody(PsiField psiField,PsiClass psiClass,PsiElementFactory factory){
        String paramName = psiField.getName();
        String paramType = psiField.getType().getCanonicalText();
        String returnType = psiClass.getName();

        String methodName = "valueOf"+StringUtils.capitalize(paramName);

        for (PsiMethod psiMethod:psiClass.findMethodsByName(methodName,true)){
            psiMethod.delete();
        }

        String body =  "public static "+returnType+" "+methodName+"("+paramType+" "+paramName+") {\n" +
                "        for ("+returnType+" obj : "+returnType+".values()) {\n" +
                "            if (java.util.Objects.equals(obj."+paramName+","+paramName+") "+") {\n" +
                "                return obj;\n" +
                "            }\n" +
                "        }\n" +
                "        return Null;\n" +
                "    }";
        PsiMethod psiMethod = factory.createMethodFromText(body,psiClass);
        psiClass.add(psiMethod);
    }

    /**
     * 添加get方法
     * @param psiField
     * @param psiClass
     * @param factory
     */
    private void addGetMethod(PsiField psiField,PsiClass psiClass,PsiElementFactory factory){
        String paramName = psiField.getName();
        String paramType = psiField.getType().getCanonicalText();
        boolean isBool = StringUtils.containsIgnoreCase(paramType,"boolean");

        String methodName = (isBool?"is":"get")+StringUtils.capitalize(paramName);
        for (PsiMethod psiMethod:psiClass.findMethodsByName(methodName,true)){
            psiMethod.delete();
        }

        String body = "public "+paramType+" "+methodName+"() {\n" +
                "        return "+paramName+";\n" +
                "    }";


        PsiMethod psiMethod = factory.createMethodFromText(body,psiClass);
        psiClass.add(psiMethod);
    }

}
